package zheezes.eisp.collect.model.impl.gd;

import java.util.Calendar;
import java.util.List;

import org.apache.log4j.Logger;

import zheezes.eisp.collect.model.ConResMeterDailyFrozenCollectTaskHandler;
import zheezes.eisp.data.orm.Concentrator;
import zheezes.eisp.data.orm.ResMeter;
import zheezes.eisp.data.orm.ResMeterDailyFrozenData;
import zheezes.protocol.Frame;
import zheezes.protocol.impl.gd.Ctrl12Frame;
import zheezes.protocol.impl.gd.Ctrl92Frame;
import zheezes.protocol.impl.gd.GdConAddr;
import zheezes.protocol.impl.gd.bean.AbstractMeterData;
import zheezes.protocol.impl.gd.bean.MeterData;
import zheezes.protocol.impl.gd.bean.SimpleMeterData;
import zheezes.socket.Transput;
import zheezes.util.ArrayUtil;


public class GdConResMeterDailyFrozenCollectTaskHandler extends ConResMeterDailyFrozenCollectTaskHandler {
	private static Logger logger = Logger.getLogger(GdConResMeterDailyFrozenCollectTaskHandler.class);
	
	static {
		logger.debug("loading");
	}

	public void run() {
		List<ResMeter> list = load();
		Calendar cal = Calendar.getInstance();
		cal.setTime(task.getDataDate());
		Concentrator con = dataAccessor.getConById(task.getConId());
		int scnt = 0;
		int failCnt = 0; // if concentrator comm failure to much, exit the task
		
		logger.debug(String.format("size = %d, terminated = %b", list.size(), terminated));
		Ctrl12Frame frame = new Ctrl12Frame();
		frame.setRtua(new GdConAddr(con.getLogicAddr()));
		for (int i = 0, n = list.size(); i < n && !terminated; i += batch) { // you should not to modify list
			ResMeter meter = list.get(i);
			frame.setOption((short) 0x4001);
			frame.setStart(meter.getSeq().shortValue());
			frame.setAmount((short) batch);
			frame.setCal(cal);
			
			// mailbox.clear();
			Transput transput;
			if((transput = postOffice.send(frame)) != null) {
				Frame[] recv = null;
				if(transput.await() == Transput.SUCCESS && (recv = transput.getRecv()) != null) {
					task.setCommSuccNum(task.getCommSuccNum() + 1);
					// Object message = null;
					for(Frame message: recv) {
					// while((message = mailbox.get()) != null) {
						if((message instanceof Ctrl92Frame)) {
							Ctrl92Frame f = (Ctrl92Frame) message;
							if(frame.match(f)) {
								scnt += save(f);
								if(scnt % 10 == 0) { // speedup collect task update and calc task create
									refreshTaskStat();
									checkConResMeterDailyUse(con, cal);
								}
							} else {
								logger.warn(String.format("frame is not match when collect resident meter daily frozen data"));
								logger.warn(String.format("request frame[%d]:%s", frame.getFseq(), ArrayUtil.sprintf(frame.getBytes(), "%02X ")));
								logger.warn(String.format("request frame[%d]:%s", f.getFseq(), ArrayUtil.sprintf(f.getBytes(), "%02X ")));
							}
						}
					}	
				}
			} else {
				/**
				 * if comm is stopped or the comm to concentrator is not stable
				 */
				if(failCnt++ >= 3) {
					logger.info(String.format("the communication to %s is unsteadiness, so yield task now", con.getLogicAddr()));
					break; // break for
					// terminated = true;
				}
			}
		} // for list
		list.clear();
		task.setRunTimes(task.getRunTimes() + 1);
		if(!terminated) {
			task.setLastRunDate(Calendar.getInstance().getTime());
		}
		refreshTaskStat();
		if (scnt > 0) {
			checkConResMeterDailyUse(con, cal);
		}
	}

	private int save(Ctrl92Frame frame) {
		int scnt = 0;
		for (MeterData mdb : frame.getMetersData()) {
			AbstractMeterData amd = mdb.getData();
			if (amd instanceof SimpleMeterData) {
				SimpleMeterData smd = (SimpleMeterData) amd;
				ResMeter rm;
				ResMeterDailyFrozenData dd = new ResMeterDailyFrozenData();
				if ((rm = findByNo(mdb.getNo())) != null) {
					dd.setMpid(rm.getMpId());
					dd.setDate(task.getDataDate());
					dd.setPp(smd.getValue());
					if(dataAccessor.saveResMeterDailyFrozenData(dd) == 0) {
						scnt++;
					} else {
						logger.info("save resisdent failure");
					}
				}
			}
		}
		logger.info(String.format("success collect %d resident meter in task[id=%d]", scnt, task.getId()));
		return scnt;
	}
}
